 import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
 import { Background } from '../effect/background'
 import { Radar } from '../effect/radar'
 import { Wall } from '../effect/wall'
 import { Cone } from '../effect/cone'
 import { Fly } from '../effect/fly'
 import {Font} from '../effect/font'
 import { Snow } from '../effect/snow'
 import { Smoke } from '../effect/smoke'
 import * as TWEEN from '@tweenjs/tween.js'
 import * as THREE from 'three'

 const fbxLoader = new FBXLoader()
 export class City{
    constructor(scene,camera,controls){
        this.controls = controls
        this.height = {
            value: 5
        };
        this.time = {
            value: 0
        }
        this.top = {
            value: 5
        };
        this.flag = false
        this.tweenPosition = null
        this.tweenRotation = null
        this.camera = camera
        this.scene = scene
        this.loadCity()
    }

    loadCity(scene){
        // 加载模型并且渲染到画布上
        fbxLoader.load('/src/model/beijing.fbx',(obj)=>{
            // this.scene.add(obj)
            obj.traverse((child)=>{
                if(child.isMesh){
                    // 底部颜色
                    const meshColor = '#1B3045'
                    // 顶部颜色
                    const headColor = '#ffffff'
                    // 高度差
                    child.geometry.computeBoundingBox()
                    child.geometry.computeBoundingSphere()
                    const {max,min} = child.geometry.boundingBox
                    const size = max.z - min.z
                    // 获取建筑物外围
                    this.addEdge(child,max,min)

                    const material = new THREE.ShaderMaterial({
                        uniforms:{
                            // 当前扫描高度
                            u_height:this.height,
                            // 扫描的线条颜色
                            u_up_color:{
                                value: new THREE.Color('#4f90bb')
                            },
                            u_city_color:{
                                value: new THREE.Color(meshColor)
                            },
                            u_head_color:{
                                value: new THREE.Color(headColor)
                            },
                            u_size:{
                                value: size
                            }
                        },
                        vertexShader:`
                            varying vec3 v_position;
                            void main(){
                                v_position = position;
                                gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
                            }
                        `,
                        fragmentShader:`
                            uniform vec3 city_color;
                            varying vec3 v_position;
                            uniform vec3 u_city_color;
                            uniform vec3 u_head_color;
                            uniform float u_size;
                            uniform float u_height;
                            uniform vec3 u_up_color;
                            void main(){
                                vec3 base_color = u_city_color;
                                base_color = mix(base_color,u_head_color,v_position.z/u_size);
                                if (u_height > v_position.z && u_height < v_position.z + 6.0) {
                                   float f_index = (u_height - v_position.z) / 3.0;
                                    base_color = mix(u_up_color, base_color, abs(f_index - 1.0));
                                }
                                gl_FragColor = vec4(base_color,1.0);

                            }
                        `
                    })
                    const mesh = new THREE.Mesh(child.geometry,material)
                    //
                    mesh.position.copy(child.position)
                    mesh.rotation.copy(child.rotation)
                    mesh.scale.copy(child.scale)
                    
                    this.scene.add(mesh)
                }
            })

            this.initEffect()

        })
    }

    addEdge(child,max,min){
        const edgesGeometry = new THREE.EdgesGeometry(child.geometry)
        // 材质
        // const edgesGeometryMaterial = new THREE.LineBasicMaterial({color:'#4f90dd'})
        const edgesGeometryMaterial = new THREE.ShaderMaterial({
            uniforms:{
                line_color:{
                    value: new THREE.Color('#4f90dd')
                },
                u_height: this.height,
                u_time: this.time,
                u_max: {
                    value:max
                },
                u_min:{
                    value: min
                },
                // 扫光颜色
                live_color:{
                    value: new THREE.Color('#ffffff')
                }
            },
            vertexShader: `
            uniform float u_time;
            uniform vec3 live_color;
            uniform vec3 line_color;
            uniform vec3 u_max;
            uniform vec3 u_min;
            
            varying vec3 v_color;
            
            void main() {
              float uMax = 4.0;
              
              float rate = u_time / uMax * 2.0;
              
              if (rate > 1.0) {
                rate = 1.0;
              }
              
              float z = position.z * rate;
            
              float new_time = mod(u_time * 0.1, 1.0);
              // 扫描的位置
              float rangeY = mix(u_min.y, u_max.y, new_time);
              
              // 当前在这个区间内，显示扫描光带
              if (rangeY < position.y && rangeY > position.y - 200.0) {
                float f_index = 1.0 - sin((position.y - rangeY) / 200.0 * 3.14);
                float r = mix(live_color.r, line_color.r, f_index);
                float g = mix(live_color.g, line_color.g, f_index);
                float b = mix(live_color.b, line_color.b, f_index);
                
                v_color = vec3(r,g,b);
              } else {
                v_color = line_color;
              }
              
              gl_Position = projectionMatrix * modelViewMatrix * vec4(vec2(position), z, 1.0);
            }
          `,
          fragmentShader: `
          varying vec3 v_color;
        
          void main() {
             gl_FragColor = vec4(v_color, 1.0);
          }
        `,
        })
        // 创建线条
        const line = new THREE.LineSegments(edgesGeometry,edgesGeometryMaterial)
        // 继承建筑物偏移量和旋转
        line.scale.copy(child.scale)
        line.rotation.copy(child.rotation)
        line.position.copy(child.position)
        this.scene.add(line)
    }

    initEffect(){
        new Background(this.scene)   
        this.addClick()
        new Radar(this.scene,this.time)
        new Wall(this.scene,this.time)
        new Cone(this.scene,this.time,this.top,this.height)
        new Fly(this.scene,this.time)
        new Font(this.scene)
        this.snow = new Snow(this.scene)
        this.smoke = new Smoke(this.scene)
        this.addWheel()
    }

  // 让场景跟随鼠标的坐标进行缩放
  addWheel() {
    const body = document.body;
    body.onmousewheel = (event) => {
      const value = 30;

      // 鼠标当前的坐标信息
      const x = (event.clientX / window.innerWidth) * 2 - 1;
      const y = -(event.clientY / window.innerHeight) * 2 + 1;

      const vector = new THREE.Vector3(x, y, 0.5);

      vector.unproject(this.camera)
      vector.sub(this.camera.position).normalize()

      if (event.wheelDelta > 0) {
        this.camera.position.x += vector.x * value;
        this.camera.position.y += vector.y * value;
        this.camera.position.z += vector.z * value;

        this.controls.target.x += vector.x * value;
        this.controls.target.y += vector.y * value;
        this.controls.target.z += vector.z * value;
      } else {
        this.camera.position.x -= vector.x * value;
        this.camera.position.y -= vector.y * value;
        this.camera.position.z -= vector.z * value;

        this.controls.target.x -= vector.x * value;
        this.controls.target.y -= vector.y * value;
        this.controls.target.z -= vector.z * value;
      }
    }
  }

    addClick(){
        let flag = true

        document.onmousedown = (e)=>{
            flag = true

            document.onmousemove = ()=>{
                flag = false
            }
        }
        document.onmouseup = (e)=>{
            if(flag){
                this.clickEvent(e)
            }
            document.onmousemove = null
        }
    }

    clickEvent(event){
            // 获取到浏览器坐标
            const x = (event.clientX / window.innerWidth) * 2 - 1;
            const y = -(event.clientY / window.innerHeight) * 2 + 1;
        
            // 创建设备坐标（三维）
            const standardVector = new THREE.Vector3(x, y, 0.5);
        
            // 转化为世界坐标
            const worldVector = standardVector.unproject(this.camera);
        
            // 做序列化
            const ray = worldVector.sub(this.camera.position).normalize();
        
            // 如何实现点击选中
            // 创建一个射线发射器，用来发射一条射线
            const raycaster = new THREE.Raycaster(this.camera.position, ray);
        
            // 返回射线碰撞到的物体
            const intersects = raycaster.intersectObjects(this.scene.children, true);
            console.log(intersects)
            let point3d = null;
            if (intersects.length) {
              point3d = intersects[0]
            }
            if (point3d) {
              console.log(point3d.object.name)
              const time = 2000;
              this.tweenPosition = new TWEEN.Tween(this.camera.position).to({
                x: point3d.point.x * 2,
                y: point3d.point.y * 2,
                z: point3d.point.z * 2
              },time).start()
              this.tweenRotation = new TWEEN.Tween(this.camera.rotation).to({
                x: this.camera.rotation.x,
                y: this.camera.rotation.y,
                z: this.camera.rotation.z
              },time).start()
              
            }
    }

    start(delta){
        this.snow?.animation()
        this.smoke?.animation()
        // 保留
        if(this.tweenPosition && this.tweenRotation){
            this.tweenPosition.update()
            this.tweenRotation.update()
        }
        this.height.value += 0.4
        if(this.height.value>160){
            this.height.value = 5;
        }

        
        if(this.top.value>15||this.top.value<0){
            this.flag = !this.flag;
        }
        this.top.value += this.flag? -0.8:0.8;


        this.time.value += delta
    }


 }